43.Gün - SwiftUI Navigation: Navigation Giriş
Table of Contents
Bu proje ile SwiftUI Navigation konusuna odaklanacağız. Navigation iki ana türe ayrılır.
- Navigation drive by user interaction (kullanıcı etkileşimi ile yönlendirilen navigasyon)
- Programmatic navigation (kendi tetiklediğimiz programatik navigasyon)
Giriş #
Bir ekrandan diğer ekrana geçiş için NavigationStack
kullanılabilmektedir.
En basit biçimde NavigationLink
kullanarak şöyle bir navigation oluşturabiliriz.
NavigationStack {
NavigationLink("Tap Me") {
Text("Detail View")
}
}
Fakat burada gizli bir sorun karşımıza çıkıyor. Bu bizim için ileride ciddi performans sorunlarına yol açabilir. Örnek olarak şöyle bir DetailView
’imiz olduğunu varsayalım;
struct DetailView: View {
var number: Int
var body: some View {
Text("Detail View \(number)")
}
init(number: Int) {
self.number = number
print("Creating detail view \(number)")
}
}
ContentView
içerisinden de aşağıdaki şekilde NavigationLink
kullanarak DetailView’e erişebiliriz.
NavigationStack {
List(0..<1000) { i in
NavigationLink("Tap Me") {
DetailView(number: i)
}
}
}
Görüldüğü gibi 1000 tane detay’a gidebildiğimiz bir navigation’ımız var.
İşte sorun burada başlıyor: navigation’ı tetikleyecek herhangi bir yere tıklamayın. Xcode debug console alanına baktığınızda bir çok DetailView
instance’ının oluşturulduğunu göreceksiniz. Hatta List
’i aşağıya doğru scroll ettiğinizde hala daha instance oluşturulduğunu görebilirsiniz.
Not: DetailView initializer’da print("Creating detail view \(number)")
satırı nedeniyle, her instance oluşturulduğunda console bu yazı yazdırılmaktadır.
navigationDestination() Kullanımı #
NavigationStack {
NavigationLink("Tap Me") {
Text("Detail View")
}
}
Yukarıdaki kod bloğunda gördüğümüz gibi basit bir navigation oluşturmak için NavigationLink
içinde her bir label hem de destination sağlarız. Fakat daha gelişmiş bir navigation için, destination’ı değerden ayırabiliriz, bu sayede destination sadece ihtiyaç duyulduğunda yüklenir.
Bu işlemi iki adımda gerçekleştirebiliriz;
NavigationLink
’eHashable
protokole uygun bir değer ekleriz.- Navigation stack içine
navigationDestination()
modifier’ını ekleyerek, verilerimizi aldığında ne yapacağını söyleriz.
Swift’in yerleşik türlerinin çoğu Hashable
protokolüne uygundur. Örneğin, Int
, String
, Date
, URL
, Array ve Dictionary protokole uygundur.
İlk olarak, her biri NavigationLink
olan ve 100 sayıdan oluşan bir List
oluşturalım, dolayısıyla SwiftUI’ye bir sayıya gitmek istediğimizi söylüyoruz.
NavigationStack {
List(0..<100) { i in
NavigationLink("Select \(i)", value: i)
}
}
Yukarıdaki kodumuz tam olarak çalışmayacaktır. Çünkü NavigationLink
’in göstereceği label’i var fakat destination’ı yok.
navigationDestination() modifier’ı burada devreye giriyor: “bir tamsayıya gitmeniz istendiğinde, işte yapmanız gereken şey….” diyebiliriz. Kodumuzu şu şekilde değiştirelim;
NavigationStack {
List(0..<100) { i in
NavigationLink("Select \(i)", value: i)
}
.navigationDestination(for: Int.self) { selection in
Text("You selected \(selection)")
}
}
Bu sayede herhangi bir Int
değeri ile navigation yapmak istediğimizde, bu değer bize selection
ile verilmektedir. Bizde hedef view’ımız ile bu değeri kullanabiliriz.
Not: Birkaç farklı veri türümüz varsa, bunlara gitmek için birkaç navigationDestination()
modifier eklememiz yeterlidir. Gerçekte “bir tamsayıya gitmek istediğinizde bunu yapın, ancak bir array’e gitmek istediğinizde şunu yapın” demiş oluruz.
Yukarıdaki sistem birçok veri için harika çalışır. Ancak özel struct’lar gibi daha karmaşık veriler için hashing kullanmamız gerekir.
Hashable Nedir? #
Hashing nedir? Örneğin internetten 10GB’lık veri indirdiğimizi varsayalım. Peki her bir veri parçasının başarıyla indirildiğinden nasıl emin olabiliriz? Hashing fonksiyonu kullanarak dosyanın hash’ini alırsak kısa bir string elde ederiz. Böylelikle sunucudaki hash ile bizim indirdiğimiz dosyanın hash’ını karşılaştırabiliriz. 10GB’lık iki dosyayı karşılaştırmak yerine iki kısa string’i karşılaştırmak elbette daha kolay. Hash fonksiyonları sayesinde her biri veri parçası için hash değeri benzersizdir ve tutarlıdır. Böylece aynı dosya için her defasında aynı hash değerini elde ederiz.
Swift’te tüm property’leri Hashable
’a uygun özel bir struct oluşturursak, tüm struct’ı da Hashable
’a çok kolay bir şekilde uygun hale getirebiliriz.
Örneğin, bu struct bir UUID, bir array ve bir tamsayı içerir;
struct Student {
var id = UUID()
var name: String
var age: Int
}
Bu struct’ı Hashable
’a uygun hale getirmek için şu şekilde bir ekleme yapmamız yeterlidir.
struct Student: Hashable {
var id = UUID()
var name: String
var age: Int
}
Artık Student
struct’ımız Hashable
’a uygun olduğuna göre, tamsayılar veya array’ler gibi hem NavigationLink
hem de navigationDestination()
ile kullanılabililir.
Bu yazıyı İngilizce olarak da okuyabilirsiniz.
You can also read this article in English.